/**
 * @author revery.Top zzjun
 * @date 11/2/20 01:30
 *
 * 说明： webpack 生产环境编译配置
 */
const path = require('path');

// js压缩和分割
const TerserPlugin = require('terser-webpack-plugin');

// 过滤node_modules内容，不编译进打包文件。
const nodeExternals = require('webpack-node-externals');

// 提取css插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 压缩css插件
const optimizeCss = require('optimize-css-assets-webpack-plugin');

/**
 * webpack entry设置
 *
 * 打包入口
 * */
const getEntry = () => {
    return {
        index: './src/index.js'
    }
}

/**
 * webpack output设置
 *
 * --- 编译后，输出设置 ---
 *
 * */
const getOutput = () => {
    return {
        // 打包文件输出名称，默认为 main.js , [name]与 getEntry的设置有关，根据我上面的设置，最终打包结果为 index.js
        filename: '[name].js',

        // 打包文件输出目录
        path: path.resolve(__dirname, '../dist'),

        libraryTarget: 'commonjs2'
    };
}

/**
 * webpack plugins 设置
 *
 * webpack插件
 *
 * */
const getPlugins = () => {
    return [

        // 提取css插件
        new MiniCssExtractPlugin({
            filename: "[name].min.css"
        }),

        // 压缩css插件
        new optimizeCss({
            assetNameRegExp: /\.style\.css$/g,
            cssProcessor: require('cssnano'),
            cssProcessorOptions: {discardComments: {removeAll: true}},
            canPrint: true
        }),

    ];
}

/**
 * rules 设置
 *
 * 编译过程中，读取到的每一个文件都会经过 rules 处理
 *      test: 符合预期需要处理正则表达式
 *      use: [] , 将文件交给某个处理器进行处理。
 *      exclude: 不处理的文件路径。
 * */
const getRules = () => {
    let rules = [];

    // 处理js
    rules.push({
        test: /\.(js|jsx)$/,
        use: [
            {
                loader: 'babel-loader',
                options: {
                    // babel默认不支持react的jsx语法，需要添加另外的编译器
                    presets: [
                        "@babel/preset-env",
                        "@babel/preset-react"
                    ],

                    // 用于识别jsx中的图片资源
                    plugins: [
                        [
                            "transform-jsx-url",
                            {
                                // 目录前缀, 这里是相对于当前配置文件的位置，所以要返回上一层的src目录获取图片
                                root: '../src',
                            }
                        ],
                    ]
                }
            }
        ],

        // 这个可以忽略的，因为已经设置了全局过滤. 全局过滤设置在这里 -> externals: [nodeExternals()]
        exclude: /node_modules/,
    });

    // 处理css
    rules.push({
        test: /\.(css|less)$/,
        use: [
            MiniCssExtractPlugin.loader,
            "css-loader",
            {
                loader: "less-loader",
                options: {
                    // 用于识别 less 里面 @import 引用的 其他样式
                    lessOptions:{
                        javascriptEnabled: true
                    }
                }
            }
        ]
    });

    // 处理图片
    rules.push({
        test: /\.(png|gif|svg|ico|jpe?g)$/i,
        use: [
            {
                //这里用url-loader来处理图片
                // file-loader 与 url-loader 功能很像
                loader: 'url-loader',
                //options里面可以配置详细的处理信息
                options: {
                    /**
                     * limit: 3072,
                     * 大于3k的图片，输出成文件。少于3k的图片，编码成base64的图片格式，保存在js中。
                     * ---- 为了达到测试效果，我这里设置了，任何时候都输出文件。
                     * */
                    limit: 0,

                    /**
                     * 这个老哥一看就是输出文件的名称方式了
                     * */
                    name: './assets/[name].[ext]',     //  打包文件名
                }
            }
        ],
    });

    return {rules}
}

/**
 * 该属性为webpack4.x新增的优化项，具体参考官方文档：
 *      官方文档： https://webpack.js.org/configuration/optimization/#root
 * 这里实现了 js/css 压缩、分割
 * */
const getOptimization = () => {
    return {
        minimize: true, // 启用代码压缩
        minimizer: [
            // 压缩、分割（需要在下面定义分割内容） js
            new TerserPlugin(),

            // 压缩css
            new optimizeCss({})
        ],
        splitChunks: {
            minSize: 1, // 3kb   表示在压缩前的最小模块大小,默认值是30kb
            chunks: 'all',//同时分割同步和异步代码,推荐。
            automaticNameDelimiter: '_',//名称分隔符，默认是~
            cacheGroups: {  //默认的规则不会打包,需要单独定义
                // baseTool.js不会被打包到index.js里面
                baseTool: {
                    name: 'baseTool',
                    chunks: 'all',
                    test: /baseTool\.js/,
                    enforce: true
                }
            }
        }
    }
}

/**
 * webpack 编译配置
 * */
const webpackConfig = {
    // 打包模式，development，开发模式。production 生产模式。
    mode: 'production',

    // 打包入口
    entry: getEntry(),

    // 编译后的文件输出保存设置
    output: getOutput(),

    // 打包用到的插件
    plugins: getPlugins(),

    // 打包过程遇到的非js，进行其他预处理。webpack只能编译js文件，其他css、图片等，需要通过这个配置，设置给其他工具去处理。
    module: getRules(),

    // 设置 js/css 压缩、分割
    optimization: getOptimization(),

    // 这个是用来过滤编译时，无视 node_modules 等文件用的。
    // 也就是文章中提及的 webpack-node-externals 工具。
    externals: [nodeExternals()]

};

module.exports = webpackConfig;
